#coding=utf-8
#auth:beck shen
#date:2017-10-25

from __future__ import absolute_import


from pytw.core.tasklet import Tasklet
from pytw.tools import log

import functools

from twisted.python.compat import intToBytes
from twisted.web import server, resource, http
from twisted.internet import reactor


class HTTPFactory(server.Site):

    """
    关闭日志
    """

    def log(self, request):
        pass


class _Resource(resource.NoResource):

    """
    默认继承404
    """

    def getChildWithDefault(self, path, request):
        if path in self.children:
            return self.children[path]
        return self
       
 
ROOT_RESOURCE = _Resource()


class Route(_Resource):

    """
    中间路由节点
    """

    @classmethod
    def route(rcls, spaths, **kwargs):
        def inner(cls):
            paths = spaths
            #路径使用'/'分割,如:/admin/login/ or admin/login
            if paths.endswith('/'):
                paths = paths[:-1]
            if paths.startswith('/'):
                paths = paths[1:]
            if not paths:
                return None
            #循环从根目录开始
            parent = kwargs.pop('root', None)
            if not parent:
                parent = ROOT_RESOURCE
            paths = paths.split('/')
            #list最大index
            max_index = len(paths) - 1
            child = None
            for i, path in enumerate(paths):
                if not path:
                    continue
                child = parent.children.get(path, None)
                #如果已经存在该路径节点
                if child:
                    parent = child
                    continue
                #当为循环最后一个元素时，则为叶子节点
                if i == max_index:
                    child = cls(**kwargs)
                else:
                    child = rcls()
                #放入子对象
                parent.putChild(path, child)
                #将本次的子对象设置为父对象
                parent = child
        return inner


class LeafResource(_Resource):

    """
    叶子节点   
    """

    isLeaf = 1

    def __init__(self, **kwargs):
        self.kwargs = kwargs

    def render(self, request):
        method = getattr(self, 'render_%s'%(request.method), None)
        if not method:
            epage = resource.ErrorPage(http.NOT_ALLOWED,
                b'NOT ALLOWED',
                b'method[%s] is not allowed'%(request.method))
            return epage.render(request)

        func = functools.partial(self._render, request, method) 
        Tasklet.create(func)
        return server.NOT_DONE_YET

    def _render(self, request, method):
        try:
            body = method(request)
            if isinstance(body, unicode):
                body = body.encode('utf-8', 'ignore')

            if not isinstance(body, bytes):
                epage = resource.ErrorPage(http.INTERNAL_SERVER_ERROR,
                    b'BYTE ERROR',
                    b'return type is not bytes')
                body = epage.render(request)
        except Exception as e:
            log.err("render_error===>:", request.path, e)
            epage = resource.ErrorPage(http.INTERNAL_SERVER_ERROR,
                b'Server ERROR',
                b'occour an error when process in server')
            body = epage.render(request)

        if request.method == 'HEAD':
            if len(body) > 0:
                request.setHeader(b'content-length', intToBytes(len(body)))
            request.write(b'')
        else:
            request.setHeader(b'content-length', intToBytes(len(body)))
            request.write(body)

        request.finish()
    

def start_http_server(port, root = None, backlog=50, interface=''):
    """
    启动http服务
    """
    if not root:
        root = ROOT_RESOURCE
    factory = HTTPFactory(root)
    reactor.listenTCP(port, factory, backlog, interface)
